package comunity;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

public class Community {
	private static Community c = null;
	private HashMap<String, UserInfo> users;
	public static final String broadcastWildcard = "Broadcast";

	private Community() {
		this.users = new HashMap<>();
	}

	public BufferedReader getUserBufferedReader(String username) {
		synchronized (this) {
			return users.get(username).getBufferedReader();
		}
	}

	public PrintWriter getUserPrintWriter(String username) {
		synchronized (this) {
			return users.get(username).getPrintWriter();
		}
	}

	public void closeUserSocket(String username) throws IOException {
		synchronized (this) {
			users.get(username).closeSocket();
		}
	}

	public boolean isUserSocketClosed(String username) {
		synchronized (this) {
			return users.get(username).isSocketClose();
		}
	}

	public boolean existUserSocket(String username) {
		synchronized (this) {
			return this.users.get(username).existSocket();
		}
	}

	public void setUserSocket(String username, Socket socket/*,
			PrintWriter printWriter, BufferedReader bufferedReader*/)
			throws IOException {
		synchronized (this) {
			this.users.get(username).setSocket(socket/*, printWriter, bufferedReader*/);
		}
	}

	public boolean contains(UserInfo user) {
		synchronized (this) {
			return users.containsKey(user.getUsername());
		}
	}
	
	public boolean contains(String username) {
		synchronized (this) {
			return users.containsKey(username);
		}
	}

	public int size() {
		synchronized (this) {
			return this.users.size();
		}
	}

	public Status getUserStatus(String username) {
		synchronized (this) {
			User user = users.get(username);
			return user.getStatus();
		}
	}

	public boolean isNewUser(String username) {
		synchronized (this) {
			UserInfo user = users.get(username);
			return user.isNewUser();
		}
	}

	public void setNewUser(String username, boolean isNewUser) {
		synchronized (this) {
			UserInfo user = users.get(username);
			user.setNewUser(isNewUser);
			users.put(username, user);
		}
	}

	public GPSLocation getUserGPSLocation(String username) {
		synchronized (this) {
			User user = users.get(username);
			return user.getGPSLocation();
		}
	}

	public void setUserGPSLocation(String username, double lat, double lon) {
		synchronized (this) {
			UserInfo user = users.get(username);
			user.setLat(lat);
			user.setLon(lon);
			users.put(username, user);
		}
	}

	public void setUserStatus(String username, Status status) {
		synchronized (this) {
			UserInfo user = users.get(username);
			user.setStatus(status);
			users.put(username, user);
		}
	}

	public void addUserInfo(UserInfo user) {
		synchronized (this) {
			this.users.put(user.getUsername(), user);
		}
	}

	public boolean checkPassword(String username, String password) {
		synchronized (this) {
			UserInfo u = users.get(username);
			return u.getPsw().equals(password);
		}
	}

	public Collection<String> getUsers() {
		synchronized (this) {
			Collection<String> users = new LinkedList<>();
			for (UserInfo userInfo : this.users.values()) {
				users.add(userInfo.getUsername());
			}
			return users;
		}
	}

	public Collection<String> getOnlineUsers() {
		synchronized (this) {
			Collection<String> onlineUsers = new LinkedList<>();
			for (UserInfo userInfo : this.users.values()) {
				if (userInfo.getStatus() == Status.OFFLINE
						|| userInfo.isNewUser())
					continue;
				onlineUsers.add(userInfo.getUsername());
			}
			return onlineUsers;
		}
	}

	public List<User> getCommunityFor(String loggingUser) {
		synchronized (this) {
			List<User> contacts = new LinkedList<>();
			for (String currentUsername : users.keySet()) {
				if (currentUsername.equals(loggingUser)) {
					continue;
				}
				User user = users.get(currentUsername);
				contacts.add(user);
			}
			return contacts;
		}
	}

	/*public void updateConnectionSettings(String username, String address,
			int port) {
		synchronized (this) {
			UserInfo u = users.get(username);
			u.setAddress(address);
			u.setPort(port);
			this.addUserInfo(u);
		}
	}

	public int getUserInputPort(String username) {
		synchronized (this) {
			UserInfo u = users.get(username);
			return u.getPort();
		}
	}

	public String getUserAddress(String username) {
		synchronized (this) {
			UserInfo u = users.get(username);
			return u.getAddress();
		}
	}*/

	public synchronized static Community obtainCommunity() {
		if (c == null)
			c = new Community();
		return c;
	}
}
